-module(queue_inst).
-include("rec_dec.hrl").
-behaviour(gen_server).
-export([start/1,init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2,code_change/3]).
-define(SERVER    , ?MODULE).

start(Q) when is_record(Q,queue_rec) ->
%% lists:flatten([atom_to_list(?MODULE),binary_to_list(Q#queue_rec.id)]
	Name = gen_server:call(increm_service,{new,"Q"}),
	case gen_server:start({local, list_to_atom(Name)}, ?MODULE, [Q], []) of 
		{ok,Pid} ->
			io:format("~p is in ~p ~n",[Name,Pid]),
			Pid;
		{error,Reason} ->
			io:format("start biz_queue service failure with ~p~n",[Reason]),
			undefined
	end.

init([Q]) ->
	Saved = restore_exist_queue_rec(Q#queue_rec.id),
	Last_Index = case Saved of 
				[] ->
					0;
				A -> 
					(lists:last(A))#cust_in_q_rec.index + 1
				end,
	lists:foreach(fun(E) ->
					if 
						E#cust_in_q_rec.mobile =/= <<"">> ->
							gen_server:call(cust_service,{add,{E#cust_in_q_rec.mobile,
															   E#cust_in_q_rec.name,
															   E#cust_in_q_rec.vendor_id,
															   E#cust_in_q_rec.q_id,
															   E#cust_in_q_rec.index}
														  }
											)
					end
				end,
				Saved),
	{ok,
	{
		#queue_inst_rec{
			id = Q#queue_rec.id,
			vendor_id = Q#queue_rec.vendor_id,
			name=Q#queue_rec.name,
			notify_cond = Q#queue_rec.notify_cond,
			prefix = Q#queue_rec.prefix,
			pid = self(),
			servered_num = 0,
			in_q_num = lists:flatlength(Saved),
			cur_index = Last_Index,
			beg_time = calendar:local_time(),
			cfg = vendor_service:get({cfg,Q#queue_rec.vendor_id})
		},
		Saved,
		[]
	}
	}.		%%state {Queue Info, Cur Index, Cust Queue}
handle_call({add_cust,{<<"">>,Name}},_,{Q,Custs,LatestCusts}) ->
	Cust = newQueueInCust({undefined,Name,length(Custs) + 1,undefined},Q),
	{reply,
		Cust,{
		Q#queue_inst_rec{in_q_num = Q#queue_inst_rec.in_q_num + 1,cur_index=Q#queue_inst_rec.cur_index + 1},
		Custs ++ [Cust],
		LatestCusts
		}};
		
handle_call({add_cust,{Mobile,Name}},_,{Q,Custs,LatestCusts}) ->
	case gen_server:call(cust_service,{add,{Mobile,Name,Q#queue_inst_rec.vendor_id,Q#queue_inst_rec.id,Q#queue_inst_rec.cur_index}}) of 
	{ok,Id} ->
		Cust = case Mobile of
			undefined ->
				newQueueInCust({Mobile,Name,length(Custs) + 1,Id},Q);
			_ ->
				CC = newQueueInCust({Mobile,Name,length(Custs) + 1,Id},Q),
				postHandle(in,CC,Q)
			end,	
		{reply,
			Cust,{
			Q#queue_inst_rec{in_q_num = Q#queue_inst_rec.in_q_num + 1,cur_index=Q#queue_inst_rec.cur_index + 1},
			Custs ++ [Cust],
			LatestCusts
			}
		};
	{in_use,_} ->
		{reply,{error,"ÓÃ»§ÒÑ¾­ÔÚ¶ÓÁÐÖÐ"},{Q,Custs,LatestCusts}};
	_ ->
		{reply,{error,"System Error"},{Q,Custs,LatestCusts}}
	end;
handle_call({restore,C},_,{Q,Custs,LatestCusts}) ->
	{reply,
		C,{
			Q#queue_inst_rec{in_q_num = Q#queue_inst_rec.in_q_num + 1,cur_index=Q#queue_inst_rec.cur_index + 1},
			Custs ++ [C],
			LatestCusts
			}
	};
handle_call({del_cust,Cust_Index},Frm,{Q,Custs,LatestCusts}) ->
	handle_call({del_cust,Cust_Index,"served"},Frm,{Q,Custs,LatestCusts});
	
handle_call({del_cust,Cust_Index,Tag},_,{Q,Custs,LatestCusts}) ->
	case lists:filter(fun(C) ->
			C#cust_in_q_rec.index =:= Cust_Index
			end,
			Custs) of
	[] ->
		{reply,{error,"No Cust Found"},{Q,Custs,LatestCusts}};
	[Cust] ->
		gen_server:call(cust_service,
					{del,
						{Cust#cust_in_q_rec.name,
						Cust#cust_in_q_rec.mobile,
						Q#queue_inst_rec.vendor_id,
						Q#queue_inst_rec.id,
						Q#queue_inst_rec.cur_index}}),
		Del_Cust = 
			case {Cust#cust_in_q_rec.mobile,Tag} of 
			{undefined,_} ->
				Cust#cust_in_q_rec{out_q_time = calendar:local_time(),state = Tag};
			{_,"served"} ->
				postHandle(out,Cust#cust_in_q_rec{out_q_time = calendar:local_time(),state = Tag},Q);
			{_,"skipped"} ->
				postHandle(out,Cust#cust_in_q_rec{out_q_time = calendar:local_time(),state = Tag},Q)
			end,
		live_qrec_service:del({cust_rec,Del_Cust#cust_in_q_rec.id}),
		custqrec_service:addchange(Del_Cust),
		{
		reply,
		Cust#cust_in_q_rec{out_q_time = calendar:local_time()},
		{
			Q#queue_inst_rec{in_q_num = Q#queue_inst_rec.in_q_num - 1},
			deleteCust(Cust,Custs,
				fun(C) ->
					postHandle(out_update,C,Q)
				end),
			if 
				length(LatestCusts) < 5 ->
					LatestCusts ++ [Del_Cust];
				true ->
					(lists:nthtail(1,LatestCusts)) ++ [Del_Cust]
			end
		}
		};
	Res ->
		io:format("wrong result ~p",[Res]),
		{reply,error,[]}
		
	end;
handle_call({send_sms,Cust_Index,Content},_,{Q,Custs,LatestCusts}) ->
	case lists:filter(fun(C) ->
			C#cust_in_q_rec.index =:= Cust_Index
			end,
			Custs) of
	[] ->
		{reply,{error,"No Cust Found"},{Q,Custs,LatestCusts}};
	[Cust] ->
		{reply,
		sendSms(Q,Cust,Content),
		{Q,Custs,LatestCusts}}
	end;
	
handle_call({get,cust_list},_,{Q,Custs,LatestCusts}) ->
	io:format("Custs ~p~n",[Custs]),
	{reply,{LatestCusts,Custs},{Q,Custs,LatestCusts}};
	
handle_call({get,queue_info},_,{Q,Custs,LatestCusts}) ->
	{reply,Q,{Q,Custs,LatestCusts}};
handle_call({update_cfg,{vendor_cfg,Cfg}},_,{Q,Custs,LatestCusts}) ->
	io:format("update cfg ~p",[Cfg]),
	{reply,ok,{Q#queue_inst_rec{
				cfg = Cfg},
				Custs,
				LatestCusts
			   }
    };
	
handle_call(stop,_,{Q,Custs,LatestCusts}) ->
	lists:foreach(
		fun(Cust) ->
			live_qrec_service:del({cust_rec,Cust#cust_in_q_rec.id})
		end,
		Custs),
	{stop,"By request",ok,{Q,Custs,LatestCusts}};

handle_call(dump,_,State) ->
	io:format("~p~n",[State]),
	{reply,ok,State};
	
handle_call(_,_,State) ->
	{reply, undefined, State}.	
handle_cast(_, State) ->
	{noreply,State}.
handle_info(_, State) ->
	{noreply,State}.
terminate(_, _) ->
	ok.
code_change(_, State, _) ->
	{ok,State}.

newQueueInCust({Mobile,Name,Loc,Cust_Id},Q) ->
	live_qrec_service:addchange(#cust_in_q_rec{
		id = gen_server:call(couch_uuids,create),
		cust_id = Cust_Id,
		mobile = Mobile,
		name = Name,
		state = in_q,
		loc = Loc,
		index = Q#queue_inst_rec.cur_index, 
		q_id = Q#queue_inst_rec.id,
		vendor_id = Q#queue_inst_rec.vendor_id,
		q_name = Q#queue_inst_rec.name,
		in_q_time = calendar:local_time(),
		sms_sent_times = 0}).

deleteCust(Cust,Custs,CB) ->
	deleteCust_A(Cust,Custs,[],0,CB).
	
deleteCust_A(_,[],NewCusts,_,_) ->
	NewCusts;

deleteCust_A(Cust,[Cust|OtherCusts],NewCusts,Del_Num,CB) ->
	deleteCust_A(Cust,OtherCusts,NewCusts,Del_Num + 1,CB);

deleteCust_A(Cust,[C|OtherCusts],NewCusts,Del_Num,CB) ->
	NewC = if 
				Del_Num > 0 ->
					CB(C#cust_in_q_rec{loc = C#cust_in_q_rec.loc - Del_Num});
				true ->
					C
			end,
	deleteCust_A(Cust,
				OtherCusts,
				NewCusts ++ [NewC],
				Del_Num,CB).
	
sendSms(_,C,Content) ->
%%	gen_server:call(cust_service,{send_sms,{C#cust_in_q_rec.cust_id,queue_inst,C#cust_in_q_rec.id,Content}}),
	io:format("send sms to ~p with ~p ~n",[C,Content]),
	C#cust_in_q_rec{
		last_sms_sent_time = calendar:local_time(),
		sms_sent_times = C#cust_in_q_rec.sms_sent_times + 1
	}.
postHandle(out_update,C,Q) ->
	Content = 
		io_lib:format(
			template:get(sms_end_adv_notify),
			[C#cust_in_q_rec.loc]
			),
	case (Q#queue_inst_rec.cfg)#vendor_cfg.pre_out_notify of
	"weibo" when C#cust_in_q_rec.loc == (Q#queue_inst_rec.cfg)#vendor_cfg.pre_out_notify_cond ->
		C;
	"sms" when C#cust_in_q_rec.loc == (Q#queue_inst_rec.cfg)#vendor_cfg.pre_out_notify_cond ->
		sendSms(Q,
				C,
				lists:flatten(tools:ansi2utf8(lists:flatten(Content))));
	_ ->
		C
	end;
postHandle(out,C,Q) ->
	Content = case C#cust_in_q_rec.state of 
			"served" ->
				template:get(sms_out_queue_served);
			"skipped" ->
				template:get(sms_out_queue_skipped)
			end,
	case (Q#queue_inst_rec.cfg)#vendor_cfg.out_notify of
	"weibo" ->
		C;
	"sms" ->
		sendSms(Q,
			C,
			lists:flatten(tools:ansi2utf8(lists:flatten(Content))));
	_ ->
		C
	end;
	
postHandle(in,C,Q) ->
	Content = 
		io_lib:format(
			template:get(sms_in_queue),
			[Q#queue_inst_rec.prefix, C#cust_in_q_rec.index, C#cust_in_q_rec.loc]
			),
	case (Q#queue_inst_rec.cfg)#vendor_cfg.in_notify of
	"weibo" ->
		C;
	"sms" ->
		sendSms(Q,
				C,
				lists:flatten(tools:ansi2utf8(lists:flatten(Content))));
	_ ->
		C
	end.

restore_exist_queue_rec(Q_Id) ->
	live_qrec_service:get({queue,Q_Id}).










